﻿/*
 Copyright (c) 2009 Alvin Cho (alvincho@risklib.com)
 Copyright (c) 2009 RiskLib.com
 
 This file is part of RiskLib.NET Project. See http://www.risklib.net for more information.
 
 RiskLib.NET is an open source project. Using of RiskLib.NET is free of charge.
 It is distributed under GNU General Public License version 2 (GPLv2).
 GPLv2 can be found at http://www.risklib.net/risklib/license.
 
 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace RiskLib.DataSource
{
    public class YahooFinanceDataSource:HistoricalTextDataSource
    {
        public YahooFinanceDataSource() : base("Yahoo!Finance") { }
        Regex reTicker = new Regex("<tr([^>]*>){3}(?<code>[^<']+)([^>]*>){3}(?<name>[^<]*)([^>]*>){2}(?<market>[^<]*)(([^>]*>){2}(?<industry>[^<]*))?([^>]*>){5}</tr>");
        Regex reTickerNext = new Regex("href=\\\"(?<url>[^\"]*)\\\">\\sNext");
        Regex reQuote = new Regex("<tr><td class=\\\"yfnc_tabledata1[^>]*>(?<DataDate>\\d[^<]*)([^>]*>){2}(?<OpenPrice>[^<]*)([^>]*>){2}(?<HighPrice>[^<]*)([^>]*>){2}(?<LowPrice>[^<]*)([^>]*>){2}(?<ClosePrice>[^<]*)([^>]*>){2}(?<Volume>[^<]*)([^>]*>){2}(?<AdjClose>[^<]*)</td></tr>");
        Regex reQuoteNext = new Regex("href=\\\"(?<url>[^\"]*)\\\">\\s?Next");

        protected override IProductCode GetProductCodeFromMatch(System.Text.RegularExpressions.Match match)
        {
            SimpleProductCode code = new SimpleProductCode(match.Groups["code"].Value);
            return code;
        }

        public override HistoricalDataList GetHistoricalData(string productCode, List<FieldNameEnum> fieldList, DateTime startDate, DateTime endDate)
        {
            HistoricalDataList hList = new HistoricalDataList();
            Uri url = new Uri("http://finance.yahoo.com/q/hp?s=" + productCode + "&a=" + startDate.ToString("MM") + "&b=" + startDate.ToString("dd") + "&c=" + startDate.ToString("yyyy") + "&d=" + endDate.ToString("MM") + "&e=" + endDate.ToString("dd") + "&f=" + endDate.ToString("yyyy") + "&g=d");
            System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-us");
            bool isFinished = false;
            while (!isFinished)
            {
                SendMessage("Getting " + url.AbsoluteUri);
                string content = GetWebPage(url.AbsoluteUri);
                HistoricalData quote;

                foreach (Match m in reQuote.Matches(content))
                {
                    quote = new HistoricalData();
                    quote.ProductCode = new SimpleProductCode(productCode);
                    foreach (FieldNameEnum fName in historicalFields.Keys)
                    {
                        if (fName == FieldNameEnum.DataDate)
                            quote.Date = DateTime.Parse(m.Groups[historicalFields[FieldNameEnum.DataDate]].Value,culture);
                        double v = 0;
                        if (double.TryParse(m.Groups[historicalFields[fName]].Value, out v))
                            quote.Values.Add(fName, v);
                    }
                    HistoricalDataEventArgs args = new HistoricalDataEventArgs();
                    args.product = quote.ProductCode;
                    args.Data = quote;
                    GotHistoricalData(args);
                    if (!hList.ContainsKey(quote.Date))
                        hList.Add(quote.Date, quote);
                }
                Match mLink = reQuoteNext.Match(content);
                if (mLink == null)
                    isFinished = true;
                else
                {
                    if (mLink.Groups["url"].Value.Length > 0)
                        url = new Uri(url, mLink.Groups["url"].Value.Replace("&amp;", "&"));
                    else
                        isFinished = true;
                }
            }
            return hList;
        }

        FieldMappingList historicalFields = new FieldMappingList()
        {
            {FieldNameEnum.DataDate,"DataDate"},
            {FieldNameEnum.OpenPrice,"OpenPrice"},
            {FieldNameEnum.HighPrice,"HighPrice"},
            {FieldNameEnum.LowPrice,"LowPrice"},
            {FieldNameEnum.ClosePrice,"ClosePrice"},
            {FieldNameEnum.AdjClose,"AdjClose"},
            {FieldNameEnum.Volume,"Volume"}
        };

        public override FieldMappingList HistoricalFields
        {
            get
            {
                return historicalFields;
            }
            set
            {
                historicalFields = value;
            }
        }

    }
}
